﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Xml;
using HNAlbum.Logic.Entity;
using ImageResizer;
using System.Configuration;
using System.Linq;

namespace HNAlbum.Logic.Manager
{
    /// <summary>
    /// Album manager
    /// </summary>
    public class AlbumManager : ManagerBase
    {
        #region Constants
        private const int THUMB_WIDTH = 80;
        private const int THUMB_HEIGHT = 60;
        private const int PREVIEW_WIDTH = 640;
        private const int PREVIEW_HEIGHT = 480;
        private const int COVER_WIDTH = 160;
        private const int COVER_HEIGHT = 120;
        #endregion

        #region Properties
        /// <summary>
        /// Album list
        /// </summary>
        public Dictionary<string, HNAlbumData> AlbumCollection { get; set; }
        /// <summary>
        /// Newly created folders set
        /// </summary>
        public FolderInfo NewAlbumFolder { get; set; }
        /// <summary>
        /// Id for the next album
        /// </summary>
        private string NextAlbumId
        {
            get
            {
                //Current album count + 1
                return ToStringId(AlbumCollection.Count + 1);
            }
        }

        /// <summary>
        /// Get the demo album Id from config file
        /// </summary>
        public static string DEMO_ALBUM
        {
            get
            {
                if (ConfigurationManager.AppSettings.AllKeys.Contains("DemoAlbumId"))
                    return ConfigurationManager.AppSettings["DemoAlbumId"];
                else return "Demo";
            }
        }

        /// <summary>
        /// Get the instance of the demo album
        /// </summary>
        public HNAlbumData DemoAlbum
        {
            get
            {
                return AlbumCollection[DEMO_ALBUM];
            }
        }

        #endregion

        #region Helpers
        /// <summary>
        /// Create new album folders structure
        /// </summary>
        private void createNewAlbumFolders()
        {
            //Album folder
            DirectoryInfo albumDir = new DirectoryInfo(Path.Combine(AppPhysicalPath, ApplicationFoler.Album, NextAlbumId));
            //To remove unwanted album
            if (albumDir.Exists)
            {
                albumDir.Delete(true);
            }
            //Create the folder
            albumDir.Create();
            NewAlbumFolder.RootFolder = albumDir.FullName;
            //Sub folders
            DirectoryInfo dir = albumDir.CreateSubdirectory(HNAlbumPhoto.PHOTO_FOLDER);
            NewAlbumFolder.PhotoFolder = dir.FullName;
            dir = albumDir.CreateSubdirectory(HNAlbumPhoto.SOURCE_FOLDER);
            NewAlbumFolder.SourceFolder = dir.FullName;
            dir = albumDir.CreateSubdirectory(HNAlbumPhoto.THUMB_FOLDER);
            NewAlbumFolder.ThumbFolder = dir.FullName;

        }
        /// <summary>
        /// Create the albums info XML
        /// </summary>
        /// <returns></returns>
        private string buildAlbumXML()
        {
            StringBuilder strBuilder = new StringBuilder();
            //Open tag
            strBuilder.Append("<Albums>");
            //Per album
            foreach (KeyValuePair<string, HNAlbumData> album in AlbumCollection)
            {
                strBuilder.AppendLine(album.Value.ToCleanXMLString());
            }
            //Close tag
            strBuilder.Append("</Albums>");
            //Result
            return strBuilder.ToString();
        }
        /// <summary>
        /// Create photos info XML
        /// </summary>
        /// <param name="photos"></param>
        /// <returns></returns>
        private string buildPhotoXML(HNAlbumPhoto[] photos)
        {
            StringBuilder strBuilder = new StringBuilder();
            //Open tag
            strBuilder.Append("<Photos>");
            //Per album
            foreach (HNAlbumPhoto photo in photos)
            {
                strBuilder.AppendLine(photo.ToCleanXMLString());
            }
            //Close tag
            strBuilder.Append("</Photos>");
            //Result
            return strBuilder.ToString();
        }
        /// <summary>
        /// Delete failed uploads
        /// </summary>
        private void cleanUp()
        {
            //Delete new album folder
            DirectoryInfo newAlbumRoot = new DirectoryInfo(NewAlbumFolder.RootFolder);
            newAlbumRoot.Delete(true);
            //Clear upload folder
            CleanUploadFolder();
        }
        #endregion

        #region Public methods
        /// <summary>
        /// Instantiate an album manager
        /// <param name="loadData">Load album data y/n</param>
        /// </summary>
        public AlbumManager(bool loadData)
        {

            //New album folder info
            NewAlbumFolder = new FolderInfo();

            //Album list
            AlbumCollection = new Dictionary<string, HNAlbumData>();

            #region Load data
            if (loadData)
            {
                #region Try read album info XML
                XmlDocument xmlAlbumInfo = new XmlDocument();
                try
                {
                    string albumXMLPath = Path.Combine(AppPhysicalPath, ApplicationFoler.XML, ApplicationXMLFile.Album);
                    xmlAlbumInfo.Load(albumXMLPath);
                }
                catch (Exception ex)
                {
                    LogAndThrow(ex, HNAException.Album.CannotRead);
                }

                #endregion

                #region Load minimal album data, basic info only, not loading album photos
                XmlNodeList nodeAlbums = xmlAlbumInfo.SelectNodes("//Album");
                foreach (XmlNode nodeAlbum in nodeAlbums)
                {
                    HNAlbumData album = new HNAlbumData();
                    album.LoadXML(nodeAlbum.OuterXml);
                    album.CoverImageUrl = Path.Combine("~", ApplicationFoler.Album, album.Id, HNAlbumData.COVER_FILE);

                    AlbumCollection.Add(album.Id, album);
                }
                #endregion
            #endregion

            }
        }
        /// <summary>
        /// Create the photo album
        /// </summary>
        /// <param name="album"></param>
        /// <param name="uploadedPhotos"></param>
        public void CreateAlbum(HNAlbumData album, FileInfo[] uploadedPhotos)
        {
            try
            {
                //Create new album folder
                createNewAlbumFolders();
            }
            catch (Exception ex)
            {
                LogAndThrow(ex, HNAException.Album.CannotCreateFolder);
            }

            #region Process photos
            //List of uploaded photos - to be serialised
            List<HNAlbumPhoto> photos = new List<HNAlbumPhoto>();
            for (int i = 0; i < uploadedPhotos.Length; i++)
            {
                try
                {
                    //Photo physical file
                    FileInfo file = uploadedPhotos[i];
                    //Album photo object - to be serialised
                    HNAlbumPhoto photo = new HNAlbumPhoto();

                    //Original file name
                    photo.Name = file.Name;
                    //Caption
                    if (album.AlbumSettings.CreateDefaultCaption)
                    {
                        //Add default caption as file name without extension
                        photo.Caption = file.Name.Substring(0, file.Name.Length - 4);
                    }
                    else
                    {
                        photo.Caption = string.Empty;
                    }
                    photo.Id = ToStringId(i);

                    //Move to source folder
                    file.MoveTo(Path.Combine(NewAlbumFolder.SourceFolder, file.Name));

                    //Image builder resize settings
                    ResizeSettings resizeSettings = new ResizeSettings();
                    resizeSettings.CropMode = CropMode.Auto;

                    #region Create thumbnails
                    resizeSettings.Width = THUMB_WIDTH;
                    resizeSettings.Height = THUMB_HEIGHT;
                    ImageBuilder.Current.Build(file.FullName, Path.Combine(NewAlbumFolder.ThumbFolder, string.Format("thumb{0}.jpg", i)), resizeSettings);
                    #endregion

                    #region Create watermark preview
                    //Create the resized bitmap object
                    resizeSettings.Width = PREVIEW_WIDTH;
                    resizeSettings.Height = PREVIEW_HEIGHT;
                    Bitmap imgPreview = ImageBuilder.Current.Build(file.FullName, resizeSettings);
                    Graphics graphic = Graphics.FromImage(imgPreview);
                    graphic.DrawString(string.Format("Brought you by HNAlbum © {0}", DateTime.Now.Year), new Font("Georgia", 12, FontStyle.Italic), new SolidBrush(Color.Black), new PointF(1, 1));
                    graphic.DrawString(string.Format("Brought you by HNAlbum © {0}", DateTime.Now.Year), new Font("Georgia", 12, FontStyle.Italic), new SolidBrush(Color.White), new PointF(0, 0));

                    //Create copyright watermark text

                    //Then save it
                    imgPreview.Save(Path.Combine(NewAlbumFolder.PhotoFolder, photo.PreviewName), ImageFormat.Jpeg);
                    //And release it
                    imgPreview.Dispose();
                    #endregion

                    #region Album cover image
                    //Default as the 1st uploaded image
                    if (i == 0)
                    {
                        resizeSettings.Width = COVER_WIDTH;
                        resizeSettings.Height = COVER_HEIGHT;
                        ImageBuilder.Current.Build(file.FullName, Path.Combine(NewAlbumFolder.RootFolder, HNAlbumData.COVER_FILE), resizeSettings);
                    }
                    #endregion

                    //Then rename the source file with a Guid
                    string previewGuid = Guid.NewGuid().ToString();
                    file.MoveTo(Path.Combine(file.DirectoryName, previewGuid + ".hna"));

                    //Last update the album item source
                    photo.Source = file.Name;

                    //Add the the list
                    photos.Add(photo);
                }
                catch (Exception ex)
                {
                    cleanUp();
                    LogAndThrow(ex, HNAException.Album.CannotProcess);
                }
            }
            #endregion

            //Update new album Id then add it to the ablbum collection
            album.Id = NextAlbumId;
            AlbumCollection.Add(NextAlbumId, album);

            #region Create album info XML
            try
            {
                //Create XML doc
                XmlDocument xDocAlbum = new XmlDocument();
                xDocAlbum.LoadXml(buildAlbumXML());
                //Then save it
                xDocAlbum.Save(Path.Combine(AppPhysicalPath, ApplicationFoler.XML, ApplicationXMLFile.Album));
            }
            catch (Exception ex)
            {
                cleanUp();
                LogAndThrow(ex, HNAException.Album.CannotProcess);
            }
            #endregion

            #region Create photo info XML
            try
            {
                //Create XML doc
                XmlDocument xDocPhoto = new XmlDocument();
                xDocPhoto.LoadXml(buildPhotoXML(photos.ToArray()));
                //Then save it
                xDocPhoto.Save(Path.Combine(AppPhysicalPath, ApplicationFoler.Album, album.Id, HNAlbumData.PHOTO_FILE));
            }
            catch (Exception ex)
            {
                cleanUp();
                LogAndThrow(ex, HNAException.Album.CannotProcess);
            }
            #endregion
        }
        #endregion

        #region Custom classes
        /// <summary>
        /// The folders consist an album
        /// </summary>
        public class FolderInfo
        {
            public string RootFolder { get; set; }
            public string SourceFolder { get; set; }
            public string PhotoFolder { get; set; }
            public string ThumbFolder { get; set; }
        }
        #endregion
    }
}
